package com.itcanteen.medical.patient.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.itcanteen.medical.common.annotation.IgnoreResponseAdvice;
import static com.itcanteen.medical.common.constant.Constant.LocationConstant.*;
import static com.itcanteen.medical.common.constant.Constant.PatientConstant.*;
import static com.itcanteen.medical.common.constant.Constant.ErrorMsg.*;

import com.itcanteen.medical.common.exception.AdException;
import com.itcanteen.medical.common.vo.CommonResponse;
import com.itcanteen.medical.patient.config.AlipayConfig;
import com.itcanteen.medical.patient.entity.Hospital;
import com.itcanteen.medical.patient.entity.Patient;
import com.itcanteen.medical.patient.entity.Theme;
import com.itcanteen.medical.patient.request.HealthTestRequest;
import com.itcanteen.medical.patient.request.HospitalRequest;
import com.itcanteen.medical.patient.request.PatientRequest;
import com.itcanteen.medical.patient.request.SendCodeRequest;
import com.itcanteen.medical.patient.service.HospitalService;
import com.itcanteen.medical.patient.service.PatientService;
import com.itcanteen.medical.patient.service.RechargeRecordService;
import com.itcanteen.medical.patient.service.ThemeService;
import com.itcanteen.medical.patient.util.DistanceUtil;
import com.itcanteen.medical.patient.util.SendMessageServiceUtil;
import com.itcanteen.medical.patient.util.SendMsgUtil;
import io.swagger.annotations.Api;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.jms.Destination;
import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;

import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * 患者 控制层
 *
 * @author 1804A-TeamOne
 * @date 2020-12-17 18:51
 */
@RestController
@RequestMapping("/patient")
@Api
@CrossOrigin
public class PatientController {

    public static final String CURRENT_PATIENT = "current_patient";

    @Resource
    private PatientService patientService;

    @Resource
    private HospitalService hospitalService;

    @Resource
    private RechargeRecordService rechargeRecordService;

    @Resource
    private ThemeService themeService;

    @Resource
    private HttpServletRequest httpServletRequest;

    @Resource
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 登陆
     *
     * @param patientRequest 登陆请求封装类
     * @return com.itcanteen.medical.common.vo.CommonResponse
     * @throws AdException 统一异常
     */
    @PostMapping("/login")
    public CommonResponse<Object> login(@RequestBody PatientRequest patientRequest) throws AdException {
        Patient loginResponse;
        /*
         * 判断登录方式,查询数据库
         */
        if (PatientRequest.PHONE.equals(patientRequest.getMode())) {
            loginResponse = patientService.selectPatientByPhone(patientRequest.getPhone());
        } else if (PatientRequest.EMAIL.equals(patientRequest.getMode())) {
            loginResponse = patientService.selectPatientByEmail(patientRequest.getEmail());
        } else if (PatientRequest.USERNAME.equals(patientRequest.getMode())) {
            loginResponse = patientService.selectPatientByUsername(patientRequest.getUsername());
        } else {
            throw new AdException(REQUEST_PARAM_ERROR);
        }

        //如果返回的对象为空,提示账号不存在
        if (loginResponse == null) {
            return new CommonResponse<>(-1, "账号不存在");
        }

        //查询redis中登陆失败的次数
        Integer loginFail = (Integer) redisTemplate.boundHashOps("loginFail"+ loginResponse.getId())
                .get("loginFail");

        //如果5分钟内连续登陆失败5次,账户将锁定5分钟
        if (loginFail != null && loginFail.equals(MAX_ALLOW_LOGIN_FAIL)) {
            return new CommonResponse<>(-1, "失败次数过多,账户锁定5分钟");
        }

        //前台传入密码进行MD5加密与数据库密码对比
        if (patientService.encodeByMd5(patientRequest.getPassword()).equals(loginResponse.getPassword())) {
            //登陆成功,删除redis中登陆失败的次数记录
            redisTemplate.boundHashOps("loginFail"+ loginResponse.getId()).delete("loginFail");
            //将用户信息存入session
            httpServletRequest.getSession().setAttribute(CURRENT_PATIENT, loginResponse);
            return new CommonResponse<>(0, "登陆成功", loginResponse);
        } else {
            /*
             * 判断登陆失败次数
             */
            if (loginFail == null) {
                redisTemplate.boundHashOps("loginFail" + loginResponse.getId()).put("loginFail", 1);
                redisTemplate.expire("loginFail" + loginResponse.getId(), 5, TimeUnit.MINUTES);
                return new CommonResponse<>(-1, "登陆失败,还有4次机会");
            } else if (loginFail + 1 < MAX_ALLOW_LOGIN_FAIL) {
                redisTemplate.boundHashOps("loginFail" + loginResponse.getId()).put("loginFail", loginFail + 1);
                return new CommonResponse<>(-1, "登陆失败,还有" + (MAX_ALLOW_LOGIN_FAIL - (loginFail + 1)) + "次机会");
            } else {
                patientService.changeStatus(loginResponse);
                return new CommonResponse<>(-1, "失败次数过多,账户锁定5分钟");
            }
        }

    }

    /**
     * 注册
     *
     * @param registerRequest 注册请求封装类
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PostMapping("/register")
    public CommonResponse<Object> register(@RequestBody SendCodeRequest registerRequest) throws AdException {
        Patient patient;
        String code;
        String key;
        if (registerRequest.getPhone() != null) {
            patient = patientService.selectPatientByPhone(registerRequest.getPhone());
            key = redisTemplate.boundValueOps("register_phone_" + registerRequest.getPhone()).getKey();
        } else if (registerRequest.getEmail() != null) {
            patient = patientService.selectPatientByEmail(registerRequest.getEmail());
            key = redisTemplate.boundValueOps("register_email_" + registerRequest.getEmail()).getKey();
        } else {
            throw new AdException(RECORD_NOT_FOUND);
        }
        if (patient != null) {
            return new CommonResponse<>(-1, "注册失败,该账号已注册");
        }
        patient = patientService.selectPatientByUsername(registerRequest.getUsername());
        if (patient != null) {
            return new CommonResponse<>(-1, "注册失败,用户名已存在,请重新输入用户名");
        }
        code = Objects.requireNonNull(redisTemplate.boundValueOps(key).get()).toString();
        if (code == null) {
            return new CommonResponse<>(-1, "验证码已过期,请重新发送");
        } else if (!code.equals(registerRequest.getCode())) {
            return new CommonResponse<>(-1, "验证码错误");
        }
        redisTemplate.delete(key);
        patientService.register(registerRequest);
        return new CommonResponse<>(0, "注册成功");
    }

    /**
     * 注册发送验证码
     *
     * @param sendCodeRequest 发送验证码请求封装类
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PostMapping("/sendCodeForRegister")
    public CommonResponse<Object> sendCode(@RequestBody SendCodeRequest sendCodeRequest) throws AdException {
        Patient patient;
        if (sendCodeRequest.getPhone() != null) {
            patient = patientService.selectPatientByPhone(sendCodeRequest.getPhone());
        } else if (sendCodeRequest.getEmail() != null) {
            patient = patientService.selectPatientByEmail(sendCodeRequest.getEmail());
        } else {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        if (patient != null) {
            return new CommonResponse<>(-1, "注册失败,该账号已注册");
        }
        int code = getCode();
        Destination destination = null;
        Map<String, String> map = new ConcurrentHashMap<>(2);
        if (sendCodeRequest.getEmail() == null) {
            destination = new ActiveMQQueue("phone_code");
            redisTemplate.boundValueOps("register_phone_" + sendCodeRequest.getPhone()).set(String.valueOf(code), 5, TimeUnit.MINUTES);
            map.put("phone", sendCodeRequest.getPhone().toString());
        } else if (sendCodeRequest.getPhone() == null) {
            destination = new ActiveMQQueue("email_code");
            redisTemplate.boundValueOps("register_email_" + sendCodeRequest.getEmail()).set(String.valueOf(code), 5, TimeUnit.MINUTES);
            map.put("email", sendCodeRequest.getEmail());
        }
        map.put("code", String.valueOf(code));
        assert destination != null;
        jmsMessagingTemplate.convertAndSend(destination, map);
        return new CommonResponse<>(0, "短信发送成功,请查收");
    }

    /**
     * 找回密码发送验证码
     *
     * @param sendCodeRequest 发送验证码请求封装类
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PostMapping("/sendCodeForRetrieve")
    public CommonResponse<Object> sendCodeForRegister(@RequestBody SendCodeRequest sendCodeRequest) throws AdException {
        Patient patient;
        if (sendCodeRequest.getPhone() != null) {
            patient = patientService.selectPatientByPhone(sendCodeRequest.getPhone());
        } else if (sendCodeRequest.getEmail() != null) {
            patient = patientService.selectPatientByEmail(sendCodeRequest.getEmail());
        } else {
            throw new AdException(RECORD_NOT_FOUND);
        }
        if (patient == null) {
            return new CommonResponse<>(-1, "账号不存在");
        }
        int code = getCode();
        Destination destination = null;
        Map<String, String> map = new ConcurrentHashMap<>(2);
        if (sendCodeRequest.getEmail() == null) {
            destination = new ActiveMQQueue("phone_code");
            redisTemplate.boundValueOps("retrieve_phone_" + sendCodeRequest.getPhone()).set(String.valueOf(code), 5, TimeUnit.MINUTES);
            map.put("phone", sendCodeRequest.getPhone().toString());
        } else if (sendCodeRequest.getPhone() == null) {
            destination = new ActiveMQQueue("email_code");
            redisTemplate.boundValueOps("retrieve_email_" + sendCodeRequest.getEmail()).set(String.valueOf(code), 5, TimeUnit.MINUTES);
            map.put("email", sendCodeRequest.getEmail());
        }
        map.put("code", String.valueOf(code));
        assert destination != null;
        jmsMessagingTemplate.convertAndSend(destination, map);
        return new CommonResponse<>(0, "验证码发送成功,请查收");
    }

    /**
     * 修改密码
     *
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/updatePassword")
    public CommonResponse<Object> updatePassword(@RequestParam("oldPassword") String oldPassword,
                                                 @RequestParam("newPassword") String newPassword) throws AdException {
        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        if (patient.getStatus() == 0) {
            /*用户状态异常*/
            throw new AdException(ABNORMAL_ERROR);
        }
        if (StringUtils.isEmpty(oldPassword) || StringUtils.isEmpty(newPassword)) {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        if (!patient.getPassword().equals(patientService.encodeByMd5(oldPassword))) {
            throw new AdException("旧密码错误");
        }
        patientService.updatePassword(patient.getId(), newPassword, httpServletRequest.getSession());
        return new CommonResponse<>(0, "success", httpServletRequest.getSession().getAttribute(CURRENT_PATIENT));
    }

    /**
     * 找回密码
     *
     * @param sendCodeRequest 发送验证码请求封装类
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/retrievePassword")
    public CommonResponse<Object> retrievePassword(@RequestBody SendCodeRequest sendCodeRequest) throws AdException {
        String code;
        Patient patient;
        String key;
        //判断用户选择的找回密码方式,根据不同的方式查找用户信息
        if (sendCodeRequest.getPhone() != null) {
            patient = patientService.selectPatientByPhone(sendCodeRequest.getPhone());
            key = redisTemplate.boundValueOps("retrieve_phone_" + sendCodeRequest.getPhone()).getKey();
        } else if (sendCodeRequest.getEmail() != null) {
            patient = patientService.selectPatientByEmail(sendCodeRequest.getEmail());
            key = redisTemplate.boundValueOps("retrieve_email_" + sendCodeRequest.getEmail()).getKey();
        } else {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        //如果用户信息为空，提示未找到记录
        if (patient == null) {
            throw new AdException(RECORD_NOT_FOUND);
        }
        //根据key获取redis中的验证码
        code = Objects.requireNonNull(redisTemplate.boundValueOps(key).get()).toString();
        if (code == null) {
            throw new AdException("验证码已过期，请重新发送");
        } else if (!code.equals(sendCodeRequest.getCode())) {
            throw new AdException("验证码错误，请重新输入");
        }
        //根据key删除redis中的缓存
        redisTemplate.delete(key);
        //设置新密码
        patientService.updatePassword(patient.getId(), sendCodeRequest.getPassword(), httpServletRequest.getSession());
        return new CommonResponse<>(0, "success");
    }

    /**
     * 换绑手机号，获取验证码
     *
     * @param phone 手机号
     * @return com.itcanteen.medical.common.vo.CommonResponse
     * @author 1804A-TeamOne
     * @date 2020-12-17 15:02
     */
    @GetMapping("/sendCodeForBindingPhone")
    private CommonResponse<Object> sendCodeForBindingPhone(@RequestParam(value = "phone") Long phone) throws AdException {
        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        if (phone.toString().length() == PHONE_SIZE) {
            if (phone.equals(patient.getPhone())) {
                return new CommonResponse<>(-1, "您已绑定此手机号码");
            }
            Patient p = patientService.selectPatientByPhone(phone);
            if (!(phone.equals(patient.getPhone())) && p != null) {
                return new CommonResponse<>(-1, "该手机号码已绑定其他用户");
            }
            //生成6位随机数
            int code = getCode();
            redisTemplate.boundValueOps("binding_phone_" + phone).set(String.valueOf(code), 5, TimeUnit.MINUTES);
            Destination destination = new ActiveMQQueue("phone_code");
            Map<String, String> map = new ConcurrentHashMap<>(2);
            map.put("phone", phone.toString());
            map.put("code", String.valueOf(code));
            //验证码存储到redis中,设置过期时间5分钟
            jmsMessagingTemplate.convertAndSend(destination, map);
            return new CommonResponse<>(0, "验证码发送成功，请查收");
        } else {
            return new CommonResponse<>(-1, "发送失败,手机号输入错误");
        }

    }

    /**
     * 换绑邮箱，获取验证码
     *
     * @param email 邮箱
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @GetMapping("/sendCodeForBindingEmail")
    public CommonResponse<Object> sendCodeForBindingEmail(@RequestParam(value = "email") String email) throws
            AdException {
        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        //判断邮箱是否为空
        if (email != null) {
            //判断邮箱格式
            char[] c = email.toCharArray();

            if (c.length > MIN_EMAIL_SIZE && c.length < MAX_EMAIL_SIZE) {
                for (int i = 0; i < c.length; i++) {
                    if (c[0] == '0' || c[0] == '@') {
                        return new CommonResponse<>(-1, "发送失败,请输入正确的邮箱格式");
                    }
                    if (c[i] == '@') {
                        if (c[i + 1] == '0' || c[i + 1] == '1' || c[i + 1] == '2' || c[i + 1] == '3' || c[i + 1] == '4' || c[i + 1] == '5' || c[i + 1] == '6' || c[i + 1] == '7' || c[i + 1] == '8' || c[i + 1] == '9') {
                            return new CommonResponse<>(-1, "发送失败,请输入正确的邮箱格式");
                        }
                        for (int j = 0; j < i; j++) {
                            if (!Character.isDigit(c[j])) {
                                return new CommonResponse<>(-1, "发送失败,请输入正确的邮箱格式");
                            }
                        }
                        String s = email.substring(i + 1);
                        if (email.equals(patient.getEmail())) {
                            return new CommonResponse<>(-1, "您已绑定此邮箱");
                        }
                        Patient p = patientService.selectPatientByEmail(email);
                        if ((!email.equals(patient.getEmail())) && p != null) {
                            return new CommonResponse<>(-1, "该邮箱已绑定其他用户");
                        }
                        if ("qq.com".equals(s)) {
                            //生成6位随机验证码
                            int code = getCode();
                            Destination destination = new ActiveMQQueue("email_code");
                            Map<String, String> map = new ConcurrentHashMap<>(2);
                            map.put("email", email);
                            map.put("code", String.valueOf(code));
                            //验证码存储到redis中,设置过期时间5分钟
                            redisTemplate.boundValueOps("binding_email_" + email).set(String.valueOf(code), 5, TimeUnit.MINUTES);
                            jmsMessagingTemplate.convertAndSend(destination, map);
                            return new CommonResponse<>(0, "验证码发送成功，请查收");
                        }
                    }
                }
            } else {
                return new CommonResponse<>(-1, "发送失败,请输入正确的邮箱格式");
            }
            return new CommonResponse<>(0, "发送成功,邮箱格式正确");
        } else {
            //邮箱为空返回提示信息
            return new CommonResponse<>(-1, "发送失败,邮箱不能为空");
        }
    }

    /**
     * 修改个人信息
     *
     * @param patient 患者信息
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/updatePatient")
    public CommonResponse<Object> getEmail(@RequestBody Patient patient) throws AdException, ParseException {
        //获取登录session对象
        Patient patient1 = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient1 == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        //判断身份证id，并根据身份证给修改用户生日，性别
        String s = patient.getIdNumber();
        String regex = "\\d{18}|\\d{17}[\\dxX]";
        if (s.matches(regex)) {
            //获取用户身份证年份
            int year = Integer.parseInt(s.substring(6, 10));
            //获取用户身份证月份
            int month = Integer.parseInt(s.substring(10, 12));
            //获取用户身份证天数
            int day = Integer.parseInt(s.substring(12, 14));
            //根据身份证倒数第二位判断性别
            int i = Integer.parseInt(s.substring(16, 17));
            if (i % MOD_DIVIDEND == 0) {
                patient1.setSex(0);
            } else {
                patient1.setSex(1);
            }
            //当前日期
            String[] format1 = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).split("-");
            //当前年份
            int nian = Integer.parseInt(format1[0]);
            //当前月份
            int yue = Integer.parseInt(format1[1]);
            //当前天数
            int tian = Integer.parseInt(format1[2]);

            //判断身份证格式是否正确
            if (nian > year) {
                if ((nian - year) <= MAX_AGE) {
                    parseDate(patient1, s, year, month, day);

                } else {
                    return new CommonResponse<>(-1, "身份证信息不对");
                }
            } else if (nian == year) {
                if (yue >= month) {
                    if (tian >= day) {
                        parseDate(patient1, s, year, month, day);
                    } else {
                        return new CommonResponse<>(-1, "身份证信息不对");
                    }
                } else {
                    return new CommonResponse<>(-1, "身份证信息不对");
                }
            } else {
                return new CommonResponse<>(-1, "身份证信息不对");
            }
        } else {
            return new CommonResponse<>(-1, "身份证信息不对");
        }
        //更换昵称
        patient1.setNickName(patient.getNickName());
        //更改修改时间
        if (patient1.getCreateTime() == null) {
            patient1.setCreateTime(new Date());
        }
        patient1.setUpdateTime(new Date());
        //修改患者信息
        patientService.updatePatient(patient1);
        //存入session
        httpServletRequest.getSession().setAttribute("patient", patient1);
        return new CommonResponse<>(0, "修改信息成功");
    }

    /**
     * 换绑手机号
     *
     * @param phone   手机号
     * @param codeReq 验证码
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/changeBindingPhone")
    public CommonResponse<Object> changeBindingPhone(@RequestParam("phone") Long
                                                             phone, @RequestParam("code") String codeReq) throws AdException {
        Patient patient1 = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient1 == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        if (StringUtils.isEmpty(codeReq)) {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        Patient patient = patientService.selectPatientByPhone(phone);
        if (patient != null) {
            return new CommonResponse<>(-1, "该手机号已绑定用户");
        }
        String code = (String) redisTemplate.boundValueOps("binding_phone_" + phone).get();
        if (code == null) {
            return new CommonResponse<>(-1, "验证码已过期,请重新发送");
        } else if (!code.equals(codeReq)) {
            return new CommonResponse<>(-1, "验证码错误");
        }
        redisTemplate.delete("binding_phone_" + phone);
        patientService.changeBindingPhone(patient1.getId(), phone, httpServletRequest.getSession());
        return new CommonResponse<>(0, "更换绑定手机号成功");
    }

    /**
     * 换绑邮箱
     *
     * @param email   邮箱
     * @param codeReq 验证码
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/changeBindingEmail")
    public CommonResponse<Object> changeBindingEmail(@RequestParam("email") String
                                                             email, @RequestParam("code") String codeReq) throws AdException {
        Patient patient1 = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient1 == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        if (StringUtils.isEmpty(codeReq)) {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        Patient patient = patientService.selectPatientByEmail(email);
        if (patient != null) {
            return new CommonResponse<>(-1, "该邮箱已绑定用户");
        }
        Object code = redisTemplate.boundValueOps("binding_email_" + email).get();
        if (code == null) {
            return new CommonResponse<>(-1, "验证码已过期,请重新发送");
        } else if (!code.equals(codeReq)) {
            return new CommonResponse<>(-1, "验证码错误");
        }
        redisTemplate.delete("binding_email_" + email);
        patientService.changeBindingEmail(patient1.getId(), email, httpServletRequest.getSession());
        return new CommonResponse<>(0, "更换绑定邮箱成功");
    }

    /**
     * 修改积分
     *
     * @param id       患者id
     * @param integral 积分
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/changeIntegral")
    public CommonResponse<Object> changeIntegral(@RequestParam("id") Integer
                                                         id, @RequestParam("integral") Integer integral) throws AdException {
        if (id == null || id <= 0) {
            throw new AdException(REQUEST_PARAM_ERROR);
        }
        patientService.changeIntegral(id, integral);
        return new CommonResponse<>(0, "success");
    }

    /**
     * 更改用户头像信息
     *
     * @param headImages 头像<文件>
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PutMapping("/changeAvatar")
    public CommonResponse<Object> changeAvatar(@RequestParam(name = "headImages") MultipartFile headImages) throws
            AdException {
        //获取登录session对象
        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        String s;
        try {
            s = patientService.changeAvatar(patient.getId(), headImages);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AdException(OSS_ERROR);
        }
        return new CommonResponse<>(0, "头像更改成功" + s);
    }

    /**
     * 调用支付宝接口充值余额
     *
     * @param outTradeNo     商品ID
     * @param subject        商品名称
     * @param totalAmount    商品金额
     * @param body           商品描述
     * @param timeoutExpress 请求超时时间
     * @param productCode    商品Code
     * @return java.lang.String
     */
    @GetMapping("/pay")
    @IgnoreResponseAdvice
    public String pay(@RequestParam("outTradeNo") String outTradeNo,
                      @RequestParam("subject") String subject,
                      @RequestParam("totalAmount") String totalAmount,
                      @RequestParam(value = "body", required = false) String body,
                      @RequestParam(value = "timeoutExpress", required = false) String timeoutExpress,
                      @RequestParam("productCode") String productCode) throws AlipayApiException, AdException {
        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(CURRENT_PATIENT);
        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        int i = updatePatientBalance(patient.getId(), totalAmount);
        if (i > 0) {
            /*
             * 1.封装RSA签名方式
             * gatewayUrl支付宝网关
             * app_id当前支付宝账户编号
             * merchant_private_key商户私钥
             * format格式化json
             * charset字符编码 utf-8
             * alipay_public_key支付宝公钥
             * sign_type支付宝签名方式 RSA2
             */
            AlipayClient alipayClient = new DefaultAlipayClient(
                    AlipayConfig.GATEWAY_URL,
                    AlipayConfig.APP_ID,
                    AlipayConfig.MERCHANT_PRIVATE_KEY,
                    AlipayConfig.FORMAT,
                    AlipayConfig.CHARSET,
                    AlipayConfig.ALIPAY_PUBLIC_KEY,
                    AlipayConfig.SIGN_TYPE);
            //2.创建Request请求
            AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
            //3.封装对象   封装页面传递过来的参数
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
            //商品ID
            model.setOutTradeNo(outTradeNo);
            //商品名称
            model.setSubject(subject);
            //商品金额
            model.setTotalAmount(totalAmount);
            //商品描述
            model.setBody(body);
            //请求超时时间
            model.setTimeExpire(timeoutExpress);
            //商品Code
            model.setProductCode(productCode);
            request.setBizModel(model);
            //设置异步回调地址
            request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
            //设置同步回调地址
            request.setReturnUrl(AlipayConfig.RETURN_URL);
            //生成表单
            return alipayClient.pageExecute(request).getBody();
        } else {
            System.out.println("支付失败!");
            return null;
        }
    }

    /**
     * 修改患者余额
     *
     * @param patientId   患者id
     * @param totalAmount 消费总金额
     * @return int
     */
    public int updatePatientBalance(int patientId, String totalAmount) {
        //根据id查询当前用户
        Patient patient = patientService.findById(patientId);
        if (patient == null) {
            return 0;
        }
        Double payMoney = Double.valueOf(totalAmount);
        //添加充值记录
        rechargeRecordService.addRechargeRecord(patientId, payMoney);
        return patientService.updatePatientBalance(patientId, payMoney);
    }

    /**
     * 病友圈新主题创建/病友圈回复主题
     * @param theme 主题信息
     * @return com.itcanteen.medical.common.vo.CommonResponse
     */
    @PostMapping("/createTheme")
    public CommonResponse<Object> createTheme(@RequestBody Theme theme) {
        Date date = new Date();
        theme.setCreateTime(date);
        theme.setUpdateTime(date);
        if (theme.getParentId() == null) {
            theme = themeService.createTheme(theme);
        } else {
            List<Theme> childThemes = (List<Theme>) redisTemplate.boundHashOps("children_themes")
                    .get(String.valueOf(theme.getParentId()));
            if (childThemes == null) {
                childThemes = new ArrayList<>();
            }
            theme = setPatient(theme);
            childThemes.add(theme);
            redisTemplate.boundHashOps("children_themes").put(String.valueOf(theme.getParentId()), childThemes);
            theme = themeService.selectById(theme.getParentId());
            theme.setUpdateTime(date);
            themeService.updateTime(theme);
            theme.setThemes(childThemes);
        }
        theme = setPatient(theme);
        return new CommonResponse<>(0, "发表成功", theme);
    }

    /**
     * 病友圈查询
     *
     * @param keyword 搜素关键字
     * @return java.util.List
     */
    @GetMapping("/searchTheme")
    @IgnoreResponseAdvice
    public List<Theme> searchTheme(
            @RequestParam(value = "keyword", required = false, defaultValue = "") String keyword) {
        List<Theme> themes = themeService.selectThemeByKeywordOrderBy(keyword);
        for (Theme theme : themes) {
            theme = setPatient(theme);
            List<Theme> childThemes = (List<Theme>) redisTemplate.boundHashOps("children_themes")
                    .get(String.valueOf(theme.getId()));
            theme.setThemes(childThemes);
        }
        return themes;
    }

    /**
     * 为主题中的用户信息赋值
     *
     * @return com.itcanteen.medical.patient.entity.Theme
     */
    public Theme setPatient(Theme theme) {
        Patient patient = patientService.findById(theme.getFromUid());
        if (patient == null) {
            patient = new Patient();
            patient.setNickName("用户已注销");
        }
        theme.setPatient(patient);
        return theme;
    }

    /**
     * 健康测试
     *
     * @param healthTestRequest 接收患者填写的信息
     */
    @PostMapping("/healthTest")
    public CommonResponse<Object> healthTest(@RequestBody HealthTestRequest healthTestRequest) throws AdException {

        Patient patient = (Patient) httpServletRequest.getSession().getAttribute(PatientController.CURRENT_PATIENT);

        if (patient == null) {
            throw new AdException(SESSION_EXPIRATION_ERROR);
        }
        //执行业务逻辑
        HealthTestRequest healthTestRequest1 = patientService.healthTest(healthTestRequest);

        return new CommonResponse<>(0, "测试完成", healthTestRequest1);
    }

    /**
     * 发短信所需信息 发短信 验证码
     */
    @JmsListener(destination = "phone_code")
    public void sendCodeByPhone(Map<String, String> map) {
        String code = map.get("code");
        String phone = map.get("phone");
        Integer httpCode = SendMsgUtil.sendMsg(code, phone);
        if (!httpCode.equals(HTTP_CODE_OK)) {
            SendMsgUtil.sendMsg(code, phone);
        }
    }

    /**
     * 发邮件所需信息 发邮件 验证码
     */
    @JmsListener(destination = "email_code")
    public void sendCodeByEmail(Map<String, String> map) throws
            UnsupportedEncodingException, MessagingException {
        int code = Integer.parseInt(map.get("code"));
        String email = map.get("email");
        SendMessageServiceUtil.sendMessage(email, code);

    }

    /**
     * 日期类型转换
     */
    private void parseDate(Patient patient1, String s, int year, int month, int day) throws ParseException {
        patient1.setIdNumber(s);
        String month1;
        String day1;
        String time;
        if (month < DECIMAL_DIGITS) {
            month1 = "0" + month;
            if (day < DECIMAL_DIGITS) {
                day1 = "0" + day;
                time = year + "-" + month1 + "-" + day1;
            } else {
                time = year + "-" + month1 + "-" + day;
            }
        } else {
            if (day < DECIMAL_DIGITS) {
                day1 = "0" + day;
                time = year + "-" + month + "-" + day1;
            } else {
                time = year + "-" + month + "-" + day;
            }
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = simpleDateFormat.parse(time);
        patient1.setBirthDate(parse);
    }

    /**
     * 生成验证码
     *
     * @return int
     */
    public int getCode() {
        Random random = new Random();
        int code = random.nextInt(1000000);
        return code < 100000 ? code + 100000 : code;
    }

    @PostMapping("findHospitalByLocation")
    public CommonResponse<List<Hospital>> findHospitalByLocation(@RequestBody HospitalRequest hospitalRequest){
        List<Hospital> hospitals = new ArrayList<>();
        CommonResponse<List<Hospital>> response;
        List<Hospital> hospitalList = hospitalService.getAllHospital();
        if(hospitalList.size()>0){
            if(hospitalRequest.getLatitude()==null || hospitalRequest.getLongitude()==null){
                response=new CommonResponse<>(0,LOCATION_ERROR,hospitalList);
            }else{
                hospitalList.forEach(hospital -> {
                    Integer distance=DistanceUtil.getDistance(
                            hospitalRequest.getLongitude(), hospitalRequest.getLatitude(),
                            hospital.getLongitude().doubleValue(),hospital.getLatitude().doubleValue());
                    if(distance<=hospitalRequest.getDistance()){
                        hospital.setDistance(distance);
                        hospitals.add(hospital);
                    }
                });
                response=new CommonResponse<>(0,SUCCESS,hospitals);
            }
        }else{
            response=new CommonResponse<>(-1,NO_RECORD_ERROR);
        }
        return response;
    }

}